<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网络监控系统 - 安全分析仪表板</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body {
            background-color: #f8f9fa;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        .navbar-brand {
            font-weight: bold;
            color: #dc3545 !important;
        }
        .card {
            border: none;
            border-radius: 15px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px;
        }
        .card-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 15px 15px 0 0 !important;
            font-weight: bold;
        }
        .stat-card {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 15px;
            padding: 20px;
            margin-bottom: 20px;
        }
        .alert-card {
            border-left: 4px solid #dc3545;
        }
        .refresh-btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border: none;
            border-radius: 25px;
            padding: 10px 20px;
            color: white;
            font-weight: bold;
        }
        .table {
            border-radius: 10px;
            overflow: hidden;
        }
        .table thead th {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            font-weight: bold;
        }
        .badge {
            font-size: 0.8em;
        }
        .loading {
            display: none;
            text-align: center;
            padding: 20px;
        }
        .spinner-border {
            width: 3rem;
            height: 3rem;
        }
    </style>
</head>
<body>
    <!-- 导航栏 -->
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">
                <i class="bi bi-shield-check"></i> 网络监控系统
            </a>
            <div class="navbar-nav ms-auto">
                <span class="navbar-text">
                    <i class="bi bi-clock"></i> 
                    <span id="lastUpdate">未更新</span>
                </span>
                <button class="btn btn-outline-light ms-2" onclick="refreshData()">
                    <i class="bi bi-arrow-clockwise"></i> 刷新
                </button>
            </div>
        </div>
    </nav>

    <div class="container-fluid mt-4">
        <!-- 统计卡片 -->
        <div class="row mb-4">
            <div class="col-md-3">
                <div class="stat-card">
                    <div class="d-flex justify-content-between">
                        <div>
                            <h3 id="totalPackets">0</h3>
                            <p class="mb-0">总数据包</p>
                        </div>
                        <div class="align-self-center">
                            <i class="bi bi-diagram-3" style="font-size: 2rem;"></i>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-3">
                <div class="stat-card">
                    <div class="d-flex justify-content-between">
                        <div>
                            <h3 id="totalAlerts">0</h3>
                            <p class="mb-0">安全告警</p>
                        </div>
                        <div class="align-self-center">
                            <i class="bi bi-exclamation-triangle" style="font-size: 2rem;"></i>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-3">
                <div class="stat-card">
                    <div class="d-flex justify-content-between">
                        <div>
                            <h3 id="tcpPackets">0</h3>
                            <p class="mb-0">TCP包</p>
                        </div>
                        <div class="align-self-center">
                            <i class="bi bi-arrow-left-right" style="font-size: 2rem;"></i>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-3">
                <div class="stat-card">
                    <div class="d-flex justify-content-between">
                        <div>
                            <h3 id="udpPackets">0</h3>
                            <p class="mb-0">UDP包</p>
                        </div>
                        <div class="align-self-center">
                            <i class="bi bi-arrow-up-down" style="font-size: 2rem;"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <!-- 协议分布图表 -->
            <div class="col-md-4">
                <div class="card">
                    <div class="card-header">
                        <i class="bi bi-pie-chart"></i> 协议分布
                    </div>
                    <div class="card-body">
                        <canvas id="protocolChart" width="400" height="200"></canvas>
                    </div>
                </div>
            </div>

            <!-- 检测类型分布 -->
            <div class="col-md-4">
                <div class="card">
                    <div class="card-header">
                        <i class="bi bi-bar-chart"></i> 检测类型分布
                    </div>
                    <div class="card-body">
                        <canvas id="detectionChart" width="400" height="200"></canvas>
                    </div>
                </div>
            </div>

            <!-- 告警类型分布 -->
            <div class="col-md-4">
                <div class="card">
                    <div class="card-header">
                        <i class="bi bi-exclamation-triangle"></i> 告警详情分布
                    </div>
                    <div class="card-body">
                        <canvas id="alertChart" width="400" height="200"></canvas>
                    </div>
                </div>
            </div>
        </div>

        <div class="row mt-4">
            <!-- 带宽图表 -->
            <div class="col-md-7">
                <div class="card">
                    <div class="card-header">
                        <i class="bi bi-graph-up"></i> 带宽使用率 (Bytes)
                    </div>
                    <div class="card-body">
                        <canvas id="bandwidthChart" width="400" height="175"></canvas>
                    </div>
                </div>
            </div>
            <!-- Top主机图表 -->
            <div class="col-md-5">
                <div class="card">
                    <div class="card-header">
                        <i class="bi bi-reception-4"></i> Top 通信主机 (流量)
                    </div>
                    <div class="card-body">
                        <canvas id="topHostsChart" width="400" height="175"></canvas>
                    </div>
                </div>
            </div>
        </div>


        <!-- 告警列表 -->
        <div class="row mt-4">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                        <i class="bi bi-exclamation-triangle"></i> 安全告警列表
                    </div>
                    <div class="card-body">
                        <div class="loading" id="loading">
                            <div class="spinner-border text-primary" role="status">
                                <span class="visually-hidden">加载中...</span>
                            </div>
                            <p class="mt-2">正在加载告警数据...</p>
                        </div>
                        <div id="alertsTable">
                            <table class="table table-hover">
                                <thead>
                                    <tr>
                                        <th>时间</th>
                                        <th>源IP</th>
                                        <th>目标IP</th>
                                        <th>协议</th>
                                        <th>检测类型</th>
                                        <th>匹配内容</th>
                                        <th>操作</th>
                                    </tr>
                                </thead>
                                <tbody id="alertsTableBody">
                                </tbody>
                            </table>
                        </div>
                        <!-- 分页 -->
                        <nav aria-label="告警分页">
                            <ul class="pagination justify-content-center" id="pagination">
                            </ul>
                        </nav>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 告警详情模态框 -->
    <div class="modal fade" id="alertModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">告警详情</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body" id="alertModalBody">
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        let currentPage = 1;
        let protocolChart = null;
        let detectionChart = null;
        let alertChart = null;
        let bandwidthChart = null;
        let topHostsChart = null;

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function () {
            updateDashboard();
            // 设置定时刷新
            setInterval(refreshData, 30000);
        });

        // 刷新所有数据
        function refreshData() {
            console.log('正在刷新数据...');
            fetch('/api/refresh')
                .then(response => response.json())
                .then(data => {
                    if(data.status === 'success') {
                        console.log('数据刷新成功:', data.last_update);
                        updateDashboard();
                    }
                })
                .catch(error => console.error('刷新数据失败:', error));
        }

        // 更新整个仪表板
        async function updateDashboard() {
            updateSummary();
            updateProtocolChart();
            updateDetectionChart();
            updateAlertsChart();
            updateBandwidthChart();
            updateTopHostsChart();
            updateAlertsTable(currentPage);
        }

        // 更新顶部摘要卡片
        async function updateSummary() {
            try {
                const response = await fetch('/api/summary');
                const data = await response.json();
                document.getElementById('totalPackets').textContent = data.statistics.total_packets || 0;
                document.getElementById('totalAlerts').textContent = data.total_alerts || 0;
                document.getElementById('tcpPackets').textContent = data.statistics.tcp_packets || 0;
                document.getElementById('udpPackets').textContent = data.statistics.udp_packets || 0;
                if (data.last_update) {
                    document.getElementById('lastUpdate').textContent = new Date(data.last_update).toLocaleString();
                }
            } catch (error) {
                console.error('摘要信息更新失败:', error);
            }
        }

        // 更新协议图表
        async function updateProtocolChart() {
            try {
                const response = await fetch('/api/protocols');
                const data = await response.json();
                if (protocolChart) protocolChart.destroy();
                const ctx = document.getElementById('protocolChart').getContext('2d');
                protocolChart = new Chart(ctx, {
                    type: 'doughnut',
                    data: {
                        labels: Object.keys(data),
                        datasets: [{
                            data: Object.values(data),
                            backgroundColor: ['#667eea', '#764ba2', '#f8b195', '#f67280', '#c06c84', '#6c5b7b', '#355c7d'],
                        }]
                    },
                    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right' } } }
                });
            } catch (error) { console.error('协议图表更新失败:', error); }
        }

        // 更新检测类型图表
        async function updateDetectionChart() {
            try {
                const response = await fetch('/api/detection_summary');
                const data = await response.json();
                if (detectionChart) detectionChart.destroy();
                const ctx = document.getElementById('detectionChart').getContext('2d');
                detectionChart = new Chart(ctx, {
                    type: 'bar',
                    data: {
                        labels: Object.keys(data),
                        datasets: [{ label: '检测次数', data: Object.values(data), backgroundColor: '#667eea' }]
                    },
                    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } }
                });
            } catch (error) { console.error('检测类型图表更新失败:', error); }
        }

        // 更新告警详情分布图表
        async function updateAlertsChart() {
            try {
                const response = await fetch('/api/alerts?page=1&per_page=1000'); // 获取所有告警用于统计
                const responseData = await response.json();
                const alertTypes = {};
                responseData.alerts.forEach(alert => {
                    alert.alerts.forEach(a => {
                        alertTypes[a.description] = (alertTypes[a.description] || 0) + 1;
                    });
                });
                if (alertChart) alertChart.destroy();
                const ctx = document.getElementById('alertChart').getContext('2d');
                alertChart = new Chart(ctx, {
                    type: 'pie',
                    data: {
                        labels: Object.keys(alertTypes),
                        datasets: [{ data: Object.values(alertTypes), backgroundColor: ['#f8b195', '#f67280', '#c06c84', '#6c5b7b', '#355c7d'] }]
                    },
                    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right' } } }
                });
            } catch (error) { console.error('告警图表更新失败:', error); }
        }

        // 更新带宽图表
        async function updateBandwidthChart() {
            try {
                const response = await fetch('/api/bandwidth');
                const data = await response.json();
                if (bandwidthChart) bandwidthChart.destroy();
                const ctx = document.getElementById('bandwidthChart').getContext('2d');
                bandwidthChart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: data.map(d => d.time.split(' ')[1]),
                        datasets: [{
                            label: '流量 (Bytes)',
                            data: data.map(d => d.bytes),
                            borderColor: '#667eea',
                            backgroundColor: 'rgba(102, 126, 234, 0.1)',
                            fill: true,
                            tension: 0.3
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        scales: {
                            x: { title: { display: true, text: '时间' } },
                            y: { title: { display: true, text: '字节数' } }
                        }
                    }
                });
            } catch (error) { console.error('带宽图表更新失败:', error); }
        }

        // 更新Top主机图表
        async function updateTopHostsChart() {
            try {
                const response = await fetch('/api/top_hosts');
                const data = await response.json();
                if (topHostsChart) topHostsChart.destroy();
                const ctx = document.getElementById('topHostsChart').getContext('2d');
                topHostsChart = new Chart(ctx, {
                    type: 'bar',
                    data: {
                        labels: data.map(d => d.host),
                        datasets: [{
                            label: '流量 (KB)',
                            data: data.map(d => (d.bytes / 1024).toFixed(2)),
                            backgroundColor: '#764ba2'
                        }]
                    },
                    options: {
                        indexAxis: 'y',
                        responsive: true,
                        maintainAspectRatio: false,
                        scales: { x: { title: { display: true, text: '流量 (KB)' } } },
                        plugins: { legend: { display: false } }
                    }
                });
            } catch (error) { console.error('Top主机图表更新失败:', error); }
        }

        // 更新告警列表
        async function updateAlertsTable(page) {
            try {
                document.getElementById('loading').style.display = 'block';
                document.getElementById('alertsTable').style.display = 'none';

                const response = await fetch(`/api/alerts?page=${page}&per_page=10`);
                const data = await response.json();
                const alertsTableBody = document.getElementById('alertsTableBody');
                alertsTableBody.innerHTML = '';

                data.alerts.forEach((alert, index) => {
                    const row = document.createElement('tr');
                    const firstAlert = alert.alerts[0];
                    row.innerHTML = `
                        <td>${formatTime(alert.timestamp)}</td>
                        <td>${alert.src_ip}:${alert.src_port}</td>
                        <td>${alert.dst_ip}:${alert.dst_port}</td>
                        <td><span class="badge bg-primary">${alert.protocol.toUpperCase()}</span></td>
                        <td>${firstAlert.description} (${alert.detection_count > 1 ? `+${alert.detection_count-1}`: ''})</td>
                        <td><code>${escapeHtml(firstAlert.matched_text)}</code></td>
                        <td><button class="btn btn-sm btn-outline-primary" onclick="showAlertDetails(${index + (page-1)*10})">详情</button></td>
                    `;
                    alertsTableBody.appendChild(row);
                });

                updatePagination(data.page, data.pages);
                document.getElementById('loading').style.display = 'none';
                document.getElementById('alertsTable').style.display = 'block';
            } catch (error) {
                console.error('加载告警失败:', error);
                document.getElementById('loading').style.display = 'none';
            }
        }

        // 更新分页
        function updatePagination(page, totalPages) {
            const pagination = document.getElementById('pagination');
            pagination.innerHTML = '';

            const prevLi = document.createElement('li');
            prevLi.className = `page-item ${page === 1 ? 'disabled' : ''}`;
            prevLi.innerHTML = `<a class="page-link" href="#" onclick="changePage(${page - 1})">上一页</a>`;
            pagination.appendChild(prevLi);

            for (let i = 1; i <= totalPages; i++) {
                const li = document.createElement('li');
                li.className = `page-item ${i === page ? 'active' : ''}`;
                li.innerHTML = `<a class="page-link" href="#" onclick="changePage(${i})">${i}</a>`;
                pagination.appendChild(li);
            }

            const nextLi = document.createElement('li');
            nextLi.className = `page-item ${page === totalPages ? 'disabled' : ''}`;
            nextLi.innerHTML = `<a class="page-link" href="#" onclick="changePage(${page + 1})">下一页</a>`;
            pagination.appendChild(nextLi);
        }

        function changePage(page) {
            currentPage = page;
            updateAlertsTable(page);
        }

        // 显示告警详情
        async function showAlertDetails(alertId) {
            const response = await fetch(`/api/alert_details/${alertId}`);
            const alert = await response.json();
            const modalBody = document.getElementById('alertModalBody');

            let detailsHtml = `<p><strong>时间:</strong> ${formatTime(alert.timestamp)}</p>
                               <p><strong>源:</strong> ${alert.src_ip}:${alert.src_port}</p>
                               <p><strong>目的:</strong> ${alert.dst_ip}:${alert.dst_port}</p>
                               <p><strong>协议:</strong> ${alert.protocol.toUpperCase()}</p>
                               <hr>
                               <h5>检测到的告警:</h5>`;
            alert.alerts.forEach(a => {
                detailsHtml += `<div class="alert alert-danger">
                                    <p><strong>类型:</strong> ${a.description}</p>
                                    <p><strong>匹配规则:</strong> <code>${escapeHtml(a.pattern)}</code></p>
                                    <p><strong>匹配内容:</strong> <code>${escapeHtml(a.matched_text)}</code></p>
                                    <p><strong>上下文:</strong> <code>${escapeHtml(a.snippet)}</code></p>
                                </div>`;
            });

            if (alert.content_preview) {
                detailsHtml += `<hr><h5>内容预览:</h5><pre><code>${escapeHtml(alert.content_preview)}</code></pre>`;
            }

            modalBody.innerHTML = detailsHtml;
            new bootstrap.Modal(document.getElementById('alertModal')).show();
        }

        function escapeHtml(unsafe) {
            return unsafe
                 .replace(/&/g, "&amp;")
                 .replace(/</g, "&lt;")
                 .replace(/>/g, "&gt;")
                 .replace(/"/g, "&quot;")
                 .replace(/'/g, "&#039;");
        }

        function formatTime(isoString) {
            if (!isoString) return 'N/A';
            const date = new Date(isoString);
            return date.toLocaleString();
        }
    </script>
</body>
</html>